/**
 * @file	tuya_ble_service.c
 * @author	chipsea
 * @brief	
 * @version	0.1
 * @date	2020-11-30
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */

/*********************************************************************
 * INCLUDES
 */
#include "sdk_config.h"
#include "att.h"
#include "log.h"
#include "OSAL.h"
#include "gatt.h"
#include "error.h"
#include "linkdb.h"
#include "gatt_uuid.h"
#include "gattservapp.h"
#include "global_config.h"
#include "tuya_ble_service.h"
#include "tuya_ble_api.h"
#include "peripheral.h"

uint8_t pvalue_buf[1024]={0};

#define RAWPASS_RX_BUFF_SIZE	1

#define RAWPASS_TX_VALUE_HANDLE	2
#define RAWPASS_RX_VALUE_HANDLE	6

#define CS_TUYA_SERVICE_BASE_UUID_128(uuid)		0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, \
										LO_UINT16(uuid), HI_UINT16( uuid ), 0x00, 0x00

///< Rawpass GATT Profile Service UUID
//CONST uint8 tuya_ble_ServiceUUID[ATT_BT_UUID_SIZE] =
//{ 
//	LO_UINT16(TUYA_BLE_SERV_UUID), HI_UINT16(TUYA_BLE_SERV_UUID)
//};
CONST uint8 tuya_ble_ServiceUUID[ATT_UUID_SIZE] =
{ 
	CS_TUYA_SERVICE_BASE_UUID_128(TUYA_BLE_SERV_UUID)
};

///< Characteristic tx uuid
//CONST uint8 tuya_ble_TxCharUUID[ATT_BT_UUID_SIZE] =
//{ 
//	LO_UINT16(TUYA_BLE_CHAR1_UUID), HI_UINT16(TUYA_BLE_CHAR1_UUID)
//};
///< Characteristic tx uuid NOTIFY  uuid:00000002-0000-1001--8001-00805F9B07D0
CONST uint8 tuya_ble_TxCharUUID[ATT_UUID_SIZE] =
{ 
	0xD0, 0x07, 0x9B, 0x5F, 0x80, 0x00, 0x01, 0x80,
    0x01, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00
};
///< Characteristic rx uuid
//CONST uint8 tuya_ble_RxCharUUID[ATT_BT_UUID_SIZE] =
//{ 
//	LO_UINT16(TUYA_BLE_CHAR2_UUID), HI_UINT16(TUYA_BLE_CHAR2_UUID)
//};
///< Characteristic rx uuid WRITE WITHOUT RESPONSE  uuid:00000001-0000-1001--8001-00805F9B07D0
CONST uint8 tuya_ble_RxCharUUID[ATT_UUID_SIZE] =
{ 
	0xD0, 0x07, 0x9B, 0x5F, 0x80, 0x00, 0x01, 0x80,
    0x01, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
};

/*********************************************************************
 * LOCAL VARIABLES
 */
attHandleValueNoti_t notify_data;

/*********************************************************************
 * Profile Attributes - variables
 */
///< Profile Service attribute
static CONST gattAttrType_t tuya_ble_Service = { ATT_UUID_SIZE, tuya_ble_ServiceUUID };

///< Profile Characteristic 1 Properties
static uint8 tuya_ble_TxCharProps = GATT_PROP_NOTIFY;

///< Characteristic 1 Value
static uint8 tuya_ble_TxCharValue = 0;

///< Simple Profile Characteristic 1 User Description
static gattCharCfg_t tuya_ble_tx_cccd;

///< Profile Characteristic 2 Properties
static uint8 tuya_ble_RxCharProps = GATT_PROP_WRITE_NO_RSP;

///< Characteristic 2 Value
static uint8 tuya_ble_RxCharValue[RAWPASS_RX_BUFF_SIZE];

static uint8 RequestIdenifyeCharUserDesp[11] = "tuya scale\0";

/*********************************************************************
 * Profile Attributes - Table
 */
static gattAttribute_t tuya_ble_profile_attr_table[] = 
{
	///< Simple Profile Service
	{
		{ ATT_BT_UUID_SIZE, primaryServiceUUID }, 	/* type */
		GATT_PERMIT_READ,                         	/* permissions */
		0,                                        	/* handle */
		(uint8 *)&tuya_ble_Service            		/* pValue */
	},

	///< Characteristic 1 Declaration
	{
		{ ATT_BT_UUID_SIZE, characterUUID },
		GATT_PERMIT_READ,
		0,
		&tuya_ble_TxCharProps
	},

	///< Characteristic Value 1
	{
		{ ATT_UUID_SIZE, tuya_ble_TxCharUUID },
		0,
		0,
		(uint8 *)&tuya_ble_TxCharValue
	},

	///< Characteristic 1 User Description
	{
		{ ATT_BT_UUID_SIZE, clientCharCfgUUID },
		GATT_PERMIT_READ|GATT_PERMIT_WRITE,
		0,
		(uint8*)&tuya_ble_tx_cccd
	},

	// Identify connect Characteristic User Description
    { 
        { ATT_BT_UUID_SIZE, charUserDescUUID },
        GATT_PERMIT_READ, 
        0, 
        RequestIdenifyeCharUserDesp 
    },

	///< Characteristic 2 Declaration
	{
		{ ATT_BT_UUID_SIZE, characterUUID },
		GATT_PERMIT_READ,
		0,
		&tuya_ble_RxCharProps
	},

	///< Characteristic Value 2
	{
		{ ATT_UUID_SIZE, tuya_ble_RxCharUUID },
		GATT_PERMIT_WRITE,
		0,
		&tuya_ble_RxCharValue[0]
	}
};

/*********************************************************************
 * LOCAL FUNCTIONS
 */
static bStatus_t tuya_ble_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
									  uint8 *pValue, uint16 len, uint16 offset );
static void tuya_ble_HandleConnStatusCB( uint16 connHandle, uint8 changeType );

/*********************************************************************
 * PROFILE CALLBACKS
 */
CONST gattServiceCBs_t tuya_ble_ProfileCBs =
{
	NULL,
	tuya_ble_WriteAttrCB, // Write callback function pointer
	NULL                 // Authorization callback function pointer
};

/**
 * @fn      tuya_ble_add_service
 * @brief   Peripheral initialization
 * @param   cb
 * @return  none
 */
bStatus_t tuya_ble_add_service(void)
{
	uint8 status = SUCCESS;

	// Register with Link DB to receive link status change callback
	VOID linkDB_Register( tuya_ble_HandleConnStatusCB  );  

	tuya_ble_tx_cccd.connHandle = INVALID_CONNHANDLE;
	tuya_ble_tx_cccd.value = 0;
	// Register GATT attribute list and CBs with GATT Server App
	status = GATTServApp_RegisterService( tuya_ble_profile_attr_table, 
										  GATT_NUM_ATTRS( tuya_ble_profile_attr_table ),
										  &tuya_ble_ProfileCBs );

	return ( status );
}

/**
 * @fn      tuya_ble_WriteAttrCB
 * @brief   
 * @param   cb
 * @return  none
 */
static bStatus_t tuya_ble_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
									  uint8 *pValue, uint16 len, uint16 offset )
{
	LOG("write attr cb\r\n");
    bStatus_t status = SUCCESS;
    //uint8 notifyApp = 0xFF;
    // If attribute permissions require authorization to write, return error
    if ( gattPermitAuthorWrite( pAttr->permissions ) )
    {
        // Insufficient authorization
        return ( ATT_ERR_INSUFFICIENT_AUTHOR );
    }

    if ( pAttr->type.len == ATT_BT_UUID_SIZE )
    {
        // 16-bit UUID
        uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
        if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
        {
            status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
                                                     offset, GATT_CLIENT_CFG_NOTIFY );
            uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] );
            LOG("CCC333333:%d\n",charCfg);
        }
    }
    if(pAttr->handle == tuya_ble_profile_attr_table[RAWPASS_RX_VALUE_HANDLE].handle)
    {
//        LOG("receive len:%d \r\n", len);
//        for(uint8_t i=0; i<len; i++)
//        {
//            LOG("%02X ", pValue[i]);
//        }
//        LOG("\r\n");
	osal_memcpy(pvalue_buf,pValue,len);
        tuya_ble_gatt_receive_data(pvalue_buf, len);
    }
    return ( status );
}

/**
 * @fn      tuya_ble_HandleConnStatusCB
 * @brief   
 * @param   cb
 * @return  none
 */
static void tuya_ble_HandleConnStatusCB ( uint16 connHandle, uint8 changeType )
{ 
	///< Make sure this is not loopback connection
	if( connHandle != LOOPBACK_CONNHANDLE )
	{
		///< Reset Client Char Config if connection has dropped
		if( ( changeType == LINKDB_STATUS_UPDATE_REMOVED )      ||
			( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && 
			( !linkDB_Up( connHandle ) ) ) )
		{
			tuya_ble_tx_cccd.value = 0;
		}
	}
}

/**
 * @fn      tuya_ble_notify
 * @brief   
 * @param   cb
 * @return  none
 */
bStatus_t tuya_ble_notify(const uint8_t *p_data,uint16_t len)
{
    uint16 connHandle;
    
	///< If notifications enabled
	if( tuya_ble_tx_cccd.value & GATT_CLIENT_CFG_NOTIFY )
	{
//        LOG("notify len:%d \r\n", len);
//        for(uint8_t i=0; i<len; i++)
//        {
//            LOG("%02X ", p_data[i]);
//        }
//        LOG("\r\n");
        GAPRole_GetParameter( GAPROLE_CONNHANDLE, &connHandle );
        
        notify_data.len = len;
        osal_memcpy(notify_data.value, p_data, len);
		///< Set the handle
		notify_data.handle = tuya_ble_profile_attr_table[RAWPASS_TX_VALUE_HANDLE].handle;

		///< Send the Indication
		return GATT_Notification( connHandle, &notify_data, FALSE);
	}
	return bleIncorrectMode;
}
